///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.display {
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.external.ExternalInterface;
	import flash.system.Capabilities;
	
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.logging.LogEventLevel;
	
	import sugarcookie.error.ApplicationError;
	import sugarcookie.events.DataEvent;
	import sugarcookie.events.GenericEvent;
	import sugarcookie.framework.IModel;
	import sugarcookie.logger.LogMessageDispatcherTarget;
	import sugarcookie.logger.TraceTarget;
	
	/**
	 * Starting point for the framework, handles basic set-up routines.
	 */
	public class ApplicationBase extends Sprite {
		public static const TRACKING:String = "onTracking";
		
		private static var _flashPlayerVersion:Array;
		private static var _params:Object;
		private static var _displayListRoot:DisplayObject;
		
		protected var _log:ILogger;
		private var _traceTarget:TraceTarget;
		private var _loggerTarget:LogMessageDispatcherTarget;
		private var _useLogging:Boolean;
		
		/**
		 * @param useAppLoader Lets the application know if a preloader has been defined.  If one is not and this is not set to false, the application will stall out.  When set to false the private startup method is automatically called.
		 */
		public function ApplicationBase(useLogging:Boolean=true,useAppLoader:Boolean=true,tabChildren:Boolean=false) {
			super();
			
			_useLogging = useLogging;
			if (useLogging) {
				_traceTarget = new TraceTarget();
	    		_traceTarget.filters=["*"];
				_traceTarget.level = LogEventLevel.ALL;
				_traceTarget.includeDate = false;
				_traceTarget.includeTime = true;
				_traceTarget.includeCategory = true;
				_traceTarget.includeLevel = true;
				Log.addTarget(_traceTarget);
				
				_loggerTarget = new LogMessageDispatcherTarget();
				_loggerTarget.filters=["*"];
				_loggerTarget.level = LogEventLevel.ALL;
				_loggerTarget.includeDate = false;
				_loggerTarget.includeTime = false;
				_loggerTarget.includeCategory = true;
				_loggerTarget.includeLevel = true;
				//Log.addTarget(_loggerTarget);
			}
				
			_log = Log.getLogger("sugarcookie.display.ApplicationBase");
			_log.info("starting up ...");
			
			addEventListener(Event.ADDED_TO_STAGE,setAppDefaults);
			addEventListener(TRACKING,trackingHandler);
			
			this.tabChildren = tabChildren;
			
			if (!useAppLoader) startup();
		}
		
		/**
		 * Starts up the application.  This is normally called by the AppLoader class after the base swf has preloaded, but can be called automatically by passing false into the constructor.
		 */
		public function startup():void {
			_log.info("ApplicationBase.startup() method is called from the Apploader after the swf has loaded and the application added to the stage.");
		}
		
		/**
		 * Called when added to stage and sets defauts for stage alignment and scaling, collects player information and makes available passed in params.  This is an event listener for Event.ADDED_TO_STAGE.
		 * 
		 * @param evt Event object received when added to stage displaylist.
		 */
		protected function setAppDefaults(evt:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE,setAppDefaults);
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			processPlayerVersion();
			processParams();
			customDefaults();
			
			ApplicationBase._displayListRoot = parent==null?this:parent;
		}
		
		/**
		 * Called by setAppDefaults() and allows for custom processing of any application attributes that require this DisplayObject to part of the DisplayList.
		 */
		protected function customDefaults():void {
			_log.info("ApplicationBase.customDefaults() method is called by setAppDefaults() and allows for custom processing of any application attributes that require this DisplayObject to part of the DisplayList.");
		}
		
		/**
		 * Automatically called after the preloader has been removed.
		 */
		public function initDisplay():void {
			//overridden by the subclass
			throw new ApplicationError("ApplicationBase.initDisplay() method must be overridden by subclass.");
		}
		
		protected function trackingHandler(evt:GenericEvent):void {
			_log.debug("tracking call: "+evt.data.trackId);
		}
		
		protected final function setLogLevel(level:String):void {
			if (!_useLogging) return;
			
			switch (level.toUpperCase()) {
				case "ALL":
					_traceTarget.level = LogEventLevel.ALL;
					_loggerTarget.level = LogEventLevel.ALL;
					break;
				case "DEBUG":
					_traceTarget.level = LogEventLevel.DEBUG;
					_loggerTarget.level = LogEventLevel.DEBUG;
					break;
				case "ERROR":
					_traceTarget.level = LogEventLevel.ERROR;
					_loggerTarget.level = LogEventLevel.ERROR;
					break;
				case "FATAL":
					_traceTarget.level = LogEventLevel.FATAL;
					_loggerTarget.level = LogEventLevel.FATAL;
					break;
				case "INFO":
					_traceTarget.level = LogEventLevel.INFO;
					_loggerTarget.level = LogEventLevel.INFO;
					break;
				case "WARN":
					_traceTarget.level = LogEventLevel.WARN;
					_loggerTarget.level = LogEventLevel.WARN;
					break;
				default:
					throw new ApplicationError("ApplicationBase.setLogLevel() level identifer is not valid.");
					break;
			}
		}
		
		private function processPlayerVersion():void {
			ApplicationBase._flashPlayerVersion = Capabilities.version.split(" ")[1].split(",");
		}
		
		public static function get playerVersion():Array {
			return _flashPlayerVersion;
		}
		
		private function processParams():void {
			ApplicationBase._params = loaderInfo.parameters;
		}
		
		public static function get parameters():Object {
			return _params;
		}
		
		public static function get displayListRoot():DisplayObject {
			return _displayListRoot;
		}
	}
}